package fileReader.demo.reader;

import java.awt.Color;
import java.awt.Graphics;
import java.awt.geom.Point2D;
import java.util.Vector;



/**
 * All the data and functions related to the whole map can be found from here
 * Map is a storage for map layers
 */

//FIXME - näkyvyyttä muutettu
public class Map 
{
	
	private PolygonMapLayer depthArea=null;
	private PolyLineMapLayer depthContour=null;
	private PointMapLayer signSound=null;
	private ControlPointMapLayer controlPoint=null;
	private PointMapLayer rocks=null;
	private PolyLineMapLayer coastline=null;
	private PointMapLayer text=null;
	private PolygonMapLayer generarea=null;
	private PolyLineMapLayer navigline=null;
	private PolyLineMapLayer pipeline=null;
	private PolyLineMapLayer limitL=null;
	private PointMapLayer limitP=null;
	private PolygonMapLayer fwayarea=null;
	private PolyLineMapLayer river=null;
	private PolyLineMapLayer roadnrailw=null;
	private PointMapLayer obstruct=null;
	private PointMapLayer harbour=null;
	private PointMapLayer natseabed=null;
	private PolyLineMapLayer bridge=null;
	private PolyLineMapLayer leadinglne=null;
	private PolygonMapLayer builtupare=null;
	private PolygonMapLayer building=null;

	private Simulator simulator;
	
	private Vector Paths;  // Set of optimal paths after Dijkstra calculation
	private Vector VGraph; // Full visibility graph.
	
	private VisibilityGraph visGraph;
	
	public boolean ShowingPaths;	//Check if we're already showing paths, if they're shown, NOT show them again!
	public boolean ShowingVGraph;	//Check if we're already showing visibility graph
	
	public boolean ShowVGraph;		//Let's show VisibilityGraph
	public boolean ShowPaths;		//Let's show Optimal Paths
	public boolean AlrdyCalculated; //if there aren't changes no calculate everything again!!
	
	public int canvas_sizex;
	public int canvas_sizey;

	double max_x;
	private int x_translation=0;
	private int y_translation=0;
		
	private double zoom;
	private double scale_factor;
	
	
	/**
	 * Constructor for the class Map. initializes all variables.
	 *
	 */
	public Map(Simulator simulator) {
		ShowPaths = false;
		ShowVGraph = false;
		ShowingPaths = false;
		ShowingVGraph = false;
		AlrdyCalculated = false;
		controlPoint=new ControlPointMapLayer(); //For ControlPoints
		VGraph = new Vector(); //Full visibility graph
		Paths = new Vector();  //Result of the calculation, optimal paths.
		visGraph = new VisibilityGraph();
		zoom=1;
		this.simulator=simulator;
		
	}
	

	
	
	/**
	 * Calculates the graph by calling visibilitygraps InitProcess method.
	 * This method calculates the graph for both ayatem menu options.
	 */
	public void CalculateGraph()
	{
		
		if(!AlrdyCalculated)
		{ // If it hasn't been calculated, just calculate it!
			if(depthArea!=null)
			{
				System.out.println("Calculating graph...");
				visGraph.InitProcess(depthArea.getData(),controlPoint.getData()); // Build + ForceBrute + Dijkstra
				Paths=visGraph.getPaths();
				VGraph=visGraph.edgeList;
				AlrdyCalculated=true;
			}

		}
	}
	
	
	/**
	 * Draws graphs and paths to the display. 
	 * @param g graphics
	 */
	
	public void DrawVGraph(Graphics g) {
		
		if(ShowVGraph){ //If We have already the VGraph drawn, We don't need to draw it again. 
		  g.setColor(Color.BLUE);
		  for (int i = 0 ; i < VGraph.size() ; i++) {
	    		Edge c = (Edge) VGraph.elementAt(i); 
	    		c.Draw(g,scale_factor,x_translation,y_translation,zoom);
	      }
		  ShowingVGraph=true;
		}
		else if(ShowPaths){	//The opposite way
			g.setColor(Color.RED);
			for (int i = 0 ; i < Paths.size() ; i++) {
				Path p = (Path) Paths.elementAt(i); 
		    	p.Draw(g,scale_factor,x_translation,y_translation,zoom);
			}
			ShowingPaths=true;
		}
	}
	
	
	
		
	/**
	 * This method draws the map to the display. 
	 * Method goes through a polygon vector, and creates a new polygon
	 * and draws it into the screen.
	 * @param g
	 */
	public void DrawMap(Graphics g) {
		
		
		if(simulator.isLayerSelected("Deptharea")){
			if(depthArea!=null)
				depthArea.drawLayer(g,zoom,x_translation,y_translation, "deptharea");
		}
		if(simulator.isLayerSelected("Generarea")){
			if(generarea!=null)
			{
				generarea.drawLayer(g,zoom,x_translation,y_translation, "generarea");
			}
		}
		if(simulator.isLayerSelected("Signsound")){
			if(signSound!=null)
			{
				signSound.drawLayer(g,zoom,x_translation,y_translation, "signsound");
			}
		}
		if(simulator.isLayerSelected("Rocks")){
			if(rocks!=null)
			{
				rocks.drawLayer(g,zoom,x_translation,y_translation, "rock");
			}
		}
		if(simulator.isLayerSelected("Coastline")){
			if(coastline!=null)
			{
				coastline.drawLayer(g,zoom,x_translation,y_translation, "coastline");
			}
		}
		if(simulator.isLayerSelected("Builtupare")){
			if(builtupare!=null)
			{
				builtupare.drawLayer(g,zoom,x_translation,y_translation, "builtupare");
			}
		}
		if(simulator.isLayerSelected("Naviglne")){
			if(navigline!=null)
			{
				navigline.drawLayer(g,zoom,x_translation,y_translation, "navigline");
			}
		}
		if(simulator.isLayerSelected("Pipeline")){
			if(pipeline!=null)
			{
				pipeline.drawLayer(g,zoom,x_translation,y_translation, "pipeline");
			}
		}
		if(simulator.isLayerSelected("LimitL")){
			if(limitL!=null)
			{
				limitL.drawLayer(g,zoom,x_translation,y_translation, "limitl");
			}
		}
		if(simulator.isLayerSelected("LimitP")){
			if(limitP!=null)
			{
				limitP.drawLayer(g,zoom,x_translation,y_translation, "limitp");
			}
		}
		if(simulator.isLayerSelected("Fwayarea")){
			if(fwayarea!=null)
			{
				fwayarea.drawLayer(g,zoom,x_translation,y_translation, "fwayarea");
			}
		}
		if(simulator.isLayerSelected("River")){
			if(river!=null)
			{
				river.drawLayer(g,zoom,x_translation,y_translation, "river");
			}
		}
		if(simulator.isLayerSelected("Roadnrailw")){
			if(roadnrailw!=null)
			{
				roadnrailw.drawLayer(g,zoom,x_translation,y_translation, "roadnrailw");
			}
		}
		if(simulator.isLayerSelected("Obstruct")){
			if(obstruct!=null)
			{
				obstruct.drawLayer(g,zoom,x_translation,y_translation, "obstruct");
			}
		}
		if(simulator.isLayerSelected("Natseabed")){
			if(natseabed!=null)
			{
				natseabed.drawLayer(g,zoom,x_translation,y_translation, "natseabed");
			}
		}
		if(simulator.isLayerSelected("Bridge")){
			if(bridge!=null)
			{
				bridge.drawLayer(g,zoom,x_translation,y_translation, "bridge");
			}
		}
		if(simulator.isLayerSelected("Leadinglne")){
			if(leadinglne!=null)
			{
				leadinglne.drawLayer(g,zoom,x_translation,y_translation, "leadinglne");
			}
		}
		if(simulator.isLayerSelected("Building")){
			if(building!=null)
			{
				building.drawLayer(g,zoom,x_translation,y_translation, "building");
			}
		}
		if(simulator.isLayerSelected("Text")){
			if(text!=null)
			{
				text.drawLayer(g,zoom,x_translation,y_translation, "text");
			}
		}
		if(simulator.isLayerSelected("Harbour")){
			if(harbour!=null)
			{
				harbour.drawLayer(g,zoom,x_translation,y_translation, "harbour");
			}
		}
		if(simulator.isLayerSelected("Depthcontour")){
			if(depthContour!=null)
			{
				depthContour.drawLayer(g,zoom,x_translation,y_translation, "depthcontour");
			}
		}
		if(depthArea!=null&&depthContour!=null&&signSound!=null)
			simulator.setNormalCursor();
		
		if(controlPoint!=null)
		{
			controlPoint.drawLayer(g,zoom,x_translation, y_translation);
		}
		
	}	
	
	/**
	 * This method cleans the map. Basicly this initializes everything
	 * and removes elements from vectors.
	 */
	public void CleanMapLayers(){
		if(depthArea!=null)
		{
			depthArea.cleanMapLayer();
			depthArea = null;
		}
		if(depthContour!=null)
		{
			depthContour.cleanMapLayer();
			depthContour = null;
		}
		if(signSound!=null)
		{
			signSound.cleanMapLayer();
			signSound = null;
		}
		if(coastline!=null)
		{
			coastline.cleanMapLayer();
			coastline = null;
		}
		if(rocks!=null)
		{
			rocks.cleanMapLayer();
			rocks = null;
		}
		if(text!=null)
		{
			text.cleanMapLayer();
			text = null;
		}
		if(controlPoint!=null)
		{
			controlPoint.cleanMapLayer();
		}
		if(generarea!=null)
		{
			generarea.cleanMapLayer();
		}
		if(navigline!=null)
		{
			navigline.cleanMapLayer();
		}
		if(pipeline!=null)
		{
			pipeline.cleanMapLayer();
		}
		if(limitL!=null)
		{
			limitL.cleanMapLayer();
		}
		if(limitP!=null)
		{
			limitP.cleanMapLayer();
		}
		if(fwayarea!=null)
		{
			fwayarea.cleanMapLayer();
		}
		if(river!=null)
		{
			river.cleanMapLayer();
		}
		if(roadnrailw!=null)
		{
			roadnrailw.cleanMapLayer();
		}
		if(obstruct!=null)
		{
			obstruct.cleanMapLayer();
		}
		if(harbour!=null)
		{
			harbour.cleanMapLayer();
		}
		if(natseabed!=null)
		{
			natseabed.cleanMapLayer();
		}
		if(bridge!=null)
		{
			bridge.cleanMapLayer();
		}
		if(leadinglne!=null)
		{
			leadinglne.cleanMapLayer();
		}
		if(builtupare!=null)
		{
			builtupare.cleanMapLayer();
		}
		if(building!=null)
		{
			building.cleanMapLayer();
		}
	}
	
	/**
	 * This method cleans translations and zoom.
	 *
	 */
	public void CleanMapInfo(){
		this.x_translation=0;
		this.y_translation=0;
		this.zoom=1;
	}
	
	
	/**
     * This method adds a control point.
     * @param v control point to add
     * @return boolean value indicating if control point was added succesfully
     * 
     * TODO ei saa list generar-arean plle
     */
    public boolean AddControlPoint(Point2D v){
            DepthArea pol;
            DepthArea pp;
            boolean inside=false;

            if(depthArea!=null)
            {
                    for(int i=0;i<depthArea.data.size();i++)
                    {                        
                            pol=(DepthArea)depthArea.data.elementAt(i);
                            if(pol!=null)
                            {
	                            inside=pol.Inside(v,Simulator.getSelectedDepth());        
	                            //if point is inside a polygon it might be inside a hole that is deep enough
	                            if (inside)
	                            {
	                            	for(int j=0;j<pol.getHoleList().size();j++)
	                                {
	                            		pp = (DepthArea)pol.getHoleList().elementAt(j);

	                            		if(pp!=null)
	                            		{
		                            		if(pp.Inside(v)&&pp.getMinDepth()>=Simulator.getSelectedDepth())
		                            		{
		                            			controlPoint.data.add(v);
		                                        return true;
		                            		}
	                            		}
	                                }
	                            	return false;
	                            }
                            }
                    }
            }
            controlPoint.data.add(v);
            return true;
    }
	
	/**
	 * This method resets variables.
	 *
	 */
	public void ResetVars(){
		AlrdyCalculated=false; 
		ShowingPaths=false;
		ShowingVGraph=false;
	}
	
	/**
	 * This method resets info. Also removes all elements from points, vis.graph
	 * and paths.
	 *
	 */
	public void ResetInfo(){
		if(Paths.size()>0)
			Paths.removeAllElements();
		VGraph.removeAllElements();
		ShowPaths = false;
		ShowVGraph = false;
		ShowingPaths = false;
		ShowingVGraph = false;
		AlrdyCalculated = false;
	}

	/**
	 * This method calls reduce methods from layers where data can be reduced
	 * 
	 * @param i number of verteces wanted on screen
	 */
	public void reduceData(int i) {
		if(depthArea!=null){
			depthArea.reduceData(i);
		}
		if(depthContour!=null){
			depthContour.reduceData(i);
		}		
	}

	/**
	 * @return Returns the zoom.
	 */
	public double getZoom() {
		return zoom;
	}

	/**
	 * @param zoom The zoom to set.
	 */
	public void setZoom(double zoom) {
		this.zoom = zoom;
	}

	/**
	 * @return Returns the x_translation.
	 */
	public int getX_translation() {
		return x_translation;
	}

	/**
	 * @param x_translation The x_translation to set.
	 */
	public void setX_translation(int x_translation) {
		this.x_translation = x_translation;
	}

	/**
	 * @return Returns the y_translation.
	 */
	public int getY_translation() {
		return y_translation;
	}

	/**
	 * @param y_translation The y_translation to set.
	 */
	public void setY_translation(int y_translation) {
		this.y_translation = y_translation;
	}

	
	/**
	 * @return Returns the paths.
	 */
	public Vector getPaths() {
		return Paths;
	}

	/**
	 * @return Returns the controlPoint.
	 */
	public ControlPointMapLayer getControlPoint() {
		return controlPoint;
	}


	public void setPointMapLayer(PointMapLayer layer, String layerName) {	
		if(layerName.equals("rock")){
			rocks = layer;
		}else if(layerName.equals("text")){
			text = layer;
		}else if(layerName.equals("limitp")){
			limitP = layer;
		}else if(layerName.equals("obstruct")){
			obstruct = layer;
		}else if(layerName.equals("harbour")){
			harbour = layer;
		}else if(layerName.equals("natseabed")){
			natseabed = layer;
		}else if(layerName.equals("signsound")){
			signSound = layer;
		}		
	}
	
	public void setPolygonMapLayer(PolygonMapLayer layer, String layerName) {	
		if(layerName.equals("deptharea")){
			depthArea = layer;
			depthArea.calcHoleDepths(signSound.getData());
		}else if(layerName.equals("generarea")){
			generarea = layer;
		}else if(layerName.equals("fwayarea")){
			fwayarea = layer;
		}else if(layerName.equals("building")){
			building = layer;
		}else if(layerName.equals("builtupare")){
			builtupare = layer;
		}
	}
	
	public void setPolyLineMapLayer(PolyLineMapLayer layer, String layerName) {	
		if(layerName.equals("depthcontour")){
			depthContour = layer;
		}else if(layerName.equals("coastline")){
			coastline = layer;
		}else if(layerName.equals("navigline")){
			navigline = layer;
		}else if(layerName.equals("pipeline")){
			pipeline = layer;
		}else if(layerName.equals("limitl")){
			limitL = layer;
		}else if(layerName.equals("river")){
			river = layer;
		}else if(layerName.equals("roadnrailw")){
			roadnrailw = layer;
		}else if(layerName.equals("bridge")){
			bridge = layer;
		}else if(layerName.equals("leadingline")){
			leadinglne = layer;
		}
	}

}
